package com.lhy.hierarchy.emailsend.engine;

import com.lhy.hierarchy.emailsend.enums.EmailContentTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Transport;
import javax.mail.internet.*;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.Calendar;
import java.util.Map;

/**
 * 基础邮件发送类。支持继承此类进行扩展
 * @author libo
 */
@Slf4j
public abstract class AbstractEmailSender implements EmailSender {


    protected MimeMessage msg;


    protected MimeMultipart cover;


    protected String fromName;

    /**
     * 构造器
     * @param msg
     * @param fromName
     */
    public AbstractEmailSender(MimeMessage msg, String fromName) {
        this.msg = msg;
        this.fromName = fromName;
        this.cover = new MimeMultipart("mixed");
    }

    /**
     * 发送消息
     * @param to      收件人
     * @param content 发送内容
     */
    @Override
    public void send(String to, String content) {
        send(to, null, EmailContentTypeEnum.TEXT, content);
    }

    /**
     * 发送消息
     * @param tos     收件人
     * @param content 发送内容
     */
    @Override
    public void send(String[] tos, String content) {
        send(tos, null, EmailContentTypeEnum.TEXT, content);
    }

    /**
     * 发送消息
     * @param to          接收邮箱
     * @param subject     邮件主题
     * @param contentType 邮件内容格式类型
     * @param content     发送内容
     */
    @Override
    public void send(String to, String subject, EmailContentTypeEnum contentType, String content) {
        send(new String[]{to}, subject, contentType, content);
    }

    /**
     * 发送消息
     * @param to 接收邮箱
     * @param subject 邮件主题
     * @param contentType 邮件内容格式类型
     * @param templateContent 发送内容
     * @param variableParameter 参数信息
     */
    @Override
    public void send(String to, String subject, EmailContentTypeEnum contentType, String templateContent, Map<String, Object> variableParameter) {
       throw new UnsupportedOperationException("");
    }

    /**
     * 发送消息
     * @param tos 接收邮箱
     * @param subject 邮件主题
     * @param contentType 邮件内容格式类型
     * @param templateContent 发送内容
     * @param variableParameter 参数信息
     */
    @Override
    public void send(String[] tos, String subject, EmailContentTypeEnum contentType, String templateContent, Map<String, Object> variableParameter) {
        throw new UnsupportedOperationException("");
    }

    /**
     * 发送消息
     * @param tos         接收邮箱
     * @param subject     邮件主题
     * @param contentType 邮件内容格式类型
     * @param content     发送内容s
     */
    @Override
    public void send(String[] tos, String subject, EmailContentTypeEnum contentType, String content) {
        try {
            config(subject, tos, contentType, content);
            msg.setSentDate(Calendar.getInstance().getTime());
            Transport.send(msg);
        } catch (MessagingException e) {
            log.error("send the message is failure!",e);
        } finally {
            // fix issue : https://gitee.com/thundzeng/mini-email/issues/I4GS8C
            try {
                clearContentAfterSend();
            } catch (MessagingException e) {
                log.error("send the message is failure!",e);
            }
        }
    }

    /**
     * 发送消息
     * @param file     附件文件
     * @param fileName 附件文件别名
     * @return
     * @throws MessagingException
     * @throws UnsupportedEncodingException
     */
    @Override
    public EmailSender addAttachment(File file, String fileName) throws MessagingException, UnsupportedEncodingException {
        setDataHandler(new DataHandler(new FileDataSource(file)), fileName);
        return this;
    }

    /**
     * 发送消息
     * @param url     附件链接
     * @param urlName 附件链接别名
     * @return
     * @throws MessagingException
     * @throws UnsupportedEncodingException
     */
    @Override
    public EmailSender addAttachment(URL url, String urlName) throws MessagingException, UnsupportedEncodingException {
        setDataHandler(new DataHandler(url), urlName);
        return this;
    }

    /**
     * 发送消息
     * @param carbonCopies 抄送邮箱
     * @return
     * @throws MessagingException
     */
    @Override
    public EmailSender addCarbonCopy(String[] carbonCopies) throws MessagingException {
        return addRecipient(carbonCopies, Message.RecipientType.CC);
    }

    /**
     * 发送消息
     * @param blindCarbonCopies 密抄邮箱
     * @return
     * @throws MessagingException
     */
    @Override
    public EmailSender addBlindCarbonCopy(String[] blindCarbonCopies) throws MessagingException {
        return addRecipient(blindCarbonCopies, Message.RecipientType.BCC);
    }

    /**
     * 设置附件
     *
     * @param dataHandler 附件handler
     * @param fileName    附件名称
     * @throws MessagingException
     * @throws UnsupportedEncodingException
     */
    protected void setDataHandler(DataHandler dataHandler, String fileName) throws MessagingException, UnsupportedEncodingException {
        MimeBodyPart attachmentPart = new MimeBodyPart();
        attachmentPart.setDataHandler(dataHandler);
        attachmentPart.setFileName(StringUtils.isEmpty(fileName) ? MimeUtility.encodeText(dataHandler.getName()) : fileName);
        cover.addBodyPart(attachmentPart);
    }

    /**
     * 设置邮件主题、收件人、发送内容等信息
     *
     * @param subject     邮件主题
     * @param to          收件人
     * @param contentType 发送内容类型。{@link EmailContentTypeEnum}
     * @param content     发送内容
     */
    protected void config(String subject, String[] to, EmailContentTypeEnum contentType, String content) {
        try {
            msg.setFrom(new InternetAddress(fromName));
            if (!StringUtils.isEmpty(subject)) {
                msg.setSubject(subject, "UTF-8");
            }
            addRecipient(to, Message.RecipientType.TO);
            setContent(contentType, content);
        } catch (MessagingException e) {
            log.error("配置邮箱发送参数失败！",e);
        }

    }

    /**
     * 添加收件人、抄送人、密抄送人
     *
     * @param recipients    收件人、抄送人、密抄送人数据
     * @param recipientType 发送类型
     * @return MiniEmail
     * @throws MessagingException
     */
    protected EmailSender addRecipient(String[] recipients, Message.RecipientType recipientType) throws MessagingException {
        if (null != recipients && recipients.length > 0) {
            InternetAddress[] parse = InternetAddress.parse(String.join(",", recipients));
            msg.setRecipients(recipientType, parse);
        }

        return this;
    }

    /**
     * 设置发送的邮件内容
     *
     * @param content 邮件内容
     * @throws MessagingException
     */
    protected void setContent(EmailContentTypeEnum contentType, String content) throws MessagingException {
        MimeBodyPart bodyPart = new MimeBodyPart();
        bodyPart.setContent(content, contentType.getContentType());
        cover.addBodyPart(bodyPart);
        msg.setContent(cover);
    }

    /**
     * 内容发送成功后，清除发送的内容
     *
     * @throws MessagingException
     */
    protected void clearContentAfterSend() throws MessagingException {
        int count = cover.getCount();
        if (count <= 0) {
            return ;
        }
        while (cover.getCount() > 0) {
            cover.removeBodyPart(0);
        }
        msg.setContent(cover);
    }
}
